package com.elitel.frame.business.controller;

import com.elitel.common.FileWriterUtil;
import com.elitel.common.exception.BaseException;
import com.elitel.common.exception.BusinessStatementException;
import com.elitel.common.exception.SingleModeMismatchException;
import com.elitel.common.messageQueue.RabbitMQHelper;
import com.elitel.common.utils.XCommonUtils;
import com.elitel.frame.base.component.RedisCacheComponent;
import com.elitel.frame.base.service.CfgExtsqlService;
import com.elitel.frame.base.service.DBServerService;
import com.elitel.frame.business.service.ExecuteSqlService;
import com.elitel.frame.business.service.MultipleTableServerService;
import com.elitel.frame.business.service.SingleTableServerService;
import com.elitel.frame.main.entity.BaseSqlFieldType;
import com.elitel.frame.main.entity.BaseSqlconfig;
import com.elitel.frame.main.entity.CfgDb;
import com.elitel.frame.main.entity.CfgExtsql;
import com.elitel.frame.main.entity.enums.ParseSQLEnum;
import com.elitel.frame.main.entity.ext.DBServer;
import com.elitel.frame.main.entity.ext.QueryFiled;
import com.elitel.frame.main.entity.ext.ReturnData;
import com.elitel.frame.main.entity.vo.JsonDataResult;
import com.elitel.frame.main.entity.vo.JsonResult;
import com.elitel.frame.main.entity.vo.PageResponseVo;
import com.elitel.frame.main.entity.vo.ServerStatistics;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 *
 * <pre>@ProjectName：frame-business-web
 * @ClassName：MultipleTableServerController
 * @Description: TODO(脚本服务)
 * @version </pre>
 */
@Controller
@RequestMapping(value = "/business/multipleServer")
@Api(value = "/business/multipleServer", tags = "脚本服务接口")
public class MultipleTableServerController {

  private static final Logger logger = LoggerFactory.getLogger(MultipleTableServerController.class);
  @Autowired private ExecuteSqlService executeSqlService;
  @Autowired private CfgExtsqlService cfgExtsqlService;
  @Autowired private SingleTableServerService singleTableServerService;
  @Autowired private RedisCacheComponent redisCacheComponent;
  @Autowired private MultipleTableServerService multipleTableServerService;
  @Resource private DBServerService dbServerServiceImpl;
  @Resource private DBServerService dBServerServiceImpl;

  @Autowired
  private RabbitMQHelper rabbitMQHelper;

  // private static final RedisDbIndex rdi =RedisDbIndex.ZERO;
  private int rdi = 0;

  // 查看作为查询条件的字段
  @ApiOperation(value = "根据服务id获取当前服务查询字段的集合", notes = "获取当前服务的查询字段")
  @RequestMapping(value = "/selectQueryFiled", method = RequestMethod.GET)
  @ResponseBody
  @ApiImplicitParams({
    @ApiImplicitParam(
        name = "serviceID",
        value = "服务id",
        required = true,
        paramType = "query",
        dataType = "String")
  })
  public Object selectServerColumn(
      HttpServletRequest request, @RequestParam(value = "serviceID") String serviceID) {
    String sessionid = request.getSession().getId();
    String debug = request.getParameter("debug");
    JsonDataResult jsonDataResult = new JsonDataResult();
    String guid = serviceID;
    JsonResult jsonResult = new JsonResult();
    List<QueryFiled> list2 = new ArrayList<>();
    Map<String, Object> map = new HashMap<>();
    List<Map<String, String>> datalist = new ArrayList<>();
    try {
      list2 = dbServerServiceImpl.selectServerField(guid);

      for (QueryFiled queryFiled : list2) {
        Map<String, String> dataMap = new HashMap<>();
        dataMap.put("fieldname", queryFiled.getParametercode());
        if (queryFiled.getParametervalue() == null || "".equals(queryFiled.getParametervalue())) {
          dataMap.put("fieldnamecn", queryFiled.getParametercode());
        } else {
          dataMap.put("fieldnamecn", queryFiled.getParametervalue());
        }
        dataMap.put("fieldtype", queryFiled.getFieldJavaType());
        dataMap.put("showtype", queryFiled.getShowtype());
        dataMap.put("enumvalue", null);
        datalist.add(dataMap);
      }
      if (CollectionUtils.isNotEmpty(datalist)){
        //根据fieldname去重
        datalist = datalist.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(m -> m.get("fieldname")))), ArrayList::new));
      }
      jsonDataResult.setData(datalist);
      jsonDataResult.setMessage("查询成功");
      jsonDataResult.setResult(0);
      jsonResult.setData(datalist);
      jsonResult.setMsg("查询成功");
      jsonResult.setSuccess(true);
    } catch (BaseException e) {
      e.printStackTrace();
      jsonDataResult.setMessage(e.getExceptionVO().getDesc());
      jsonDataResult.setResult(Integer.valueOf(e.getExceptionVO().getValue()));
      jsonResult.setMsg("查询失败");
      jsonResult.setSuccess(false);
    }
    if ("true".equals(debug)) {
      return FileWriterUtil.txt2String(sessionid);
    } else {
      return jsonDataResult;
    }
  }

  // 数据服务是否分页
  @ApiOperation(value = "根据服务id获取当前服务是否分页", notes = "获取当前服务是否分页")
  @RequestMapping(value = "/selectIsPaging", method = RequestMethod.GET)
  @ResponseBody
  @ApiImplicitParams({
    @ApiImplicitParam(
        name = "serviceID",
        value = "服务id",
        required = true,
        paramType = "query",
        dataType = "String")
  })
  public boolean selectIsPaging(
      HttpServletRequest request, @RequestParam(value = "serviceID") String serviceID) {
    String guid = serviceID;
    DBServer dBServer = dbServerServiceImpl.selectServerOnes(guid);
    boolean ispaging = false;
    if (dBServer.getIsPaging() == 1) {
      ispaging = true;
    }
    return ispaging;
  }
  // 查询所有字段
  @ApiOperation(value = "根据服务id获取当前服务是否分页", notes = "获取当前服务是否分页")
  @RequestMapping(value = "/selectShowFiled", method = RequestMethod.GET)
  @ResponseBody
  @ApiImplicitParams({
    @ApiImplicitParam(
        name = "serviceID",
        value = "服务id",
        required = true,
        paramType = "query",
        dataType = "String")
  })
  public Object selectAllColumn(
      HttpServletRequest request, @RequestParam(value = "serviceID") String serviceID) {
    String debug = request.getParameter("debug");
    String sessionid = request.getSession().getId();
    String guid = serviceID;
    JsonResult jsonResult = new JsonResult();
    JsonDataResult jsonDataResult = new JsonDataResult();
    List<ReturnData> list2 = new ArrayList<>();
    try {

      List<BaseSqlconfig> list = dbServerServiceImpl.selectServerColumn(guid);
      for (BaseSqlconfig b : list) {
        ReturnData returnData = new ReturnData();
        returnData.setShowtype(b.getShowtype());
        returnData.setFieldtype(b.getRemark());
        returnData.setFieldname(b.getFiledname());
        // 如果是空的话 就去取字段编码
        returnData.setFieldnamecn(StringUtils.isEmpty(b.getFieldcaption()) ? b.getFiledname() : b.getFieldcaption());
//        returnData.setFieldnamecn(b.getFieldcaption());
        list2.add(returnData);
      }
      if (CollectionUtils.isNotEmpty(list)){
        //根据fileName去重
        list2 = list2.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(ReturnData::getFieldname))), ArrayList::new));
      }

      jsonResult.setMsg("查询成功");
      jsonResult.setData(list2);
      jsonResult.setSuccess(false);
      jsonDataResult.setData(list2);
      jsonDataResult.setMessage("查询成功");
      jsonDataResult.setResult(0);
    } catch (BaseException e) {
      e.printStackTrace();
      jsonResult.setData(((BaseException) e).getExceptionVO());
      jsonResult.setMsg(e.getMessage());
      jsonResult.setSuccess(false);
      jsonDataResult.setMessage(e.getExceptionVO().getDesc());
      jsonDataResult.setResult(Integer.valueOf(e.getExceptionVO().getValue()));
    }
    if ("true".equals(debug)) {
      return FileWriterUtil.txt2String(sessionid);
    } else {
      return jsonDataResult;
    }
  }
  /**
   * <pre>multipleTableServer(多表查询执行sql脚本)
   * @author：FanWenquan
   * @date：2017年8月31日 上午10:33:25
   * @param serviceID
   * @param pageNO
   * @param pageSize
   * @return</pre>
   * @throws Exception
   */
  @ApiOperation(notes = "/multipleTableServer", value = "根据服务编码执行sql脚本获取信息")
  @RequestMapping(value = "/multipleTableServer", method = {RequestMethod.POST, RequestMethod.GET})
  @ResponseBody
  @ApiImplicitParams({
          @ApiImplicitParam(
                  name = "serviceID",
                  value = "服务编码",
                  required = true,
                  dataType = "String",
                  paramType = "query"),
          @ApiImplicitParam(
                  name = "pageNO",
                  value = "当前页码",
                  required = false,
                  dataType = "String",
                  paramType = "query"),
          @ApiImplicitParam(
                  name = "pageSize",
                  value = "每页条数",
                  required = false,
                  dataType = "String",
                  paramType = "query"),
          @ApiImplicitParam(
                  name = "debug",
                  value = "是否校验",
                  required = false,
                  dataType = "boolean",
                  paramType = "query"),
          @ApiImplicitParam(
                  name = "conQuery",
                  value = "查询条件集合",
                  required = false,
                  dataType = "String",
                  paramType = "query"),
          @ApiImplicitParam(
                  name = "refCache",
                  value = "是否强制刷新缓存",
                  required = false,
                  dataType = "String",
                  paramType = "query")
  })
  public Object multipleTableServer(HttpServletRequest request,
                                    @RequestParam(value = "serviceID") String serviceID,
                                    String pageNO,
                                    String pageSize,
                                    String conQuery,
                                    String refCache) throws Exception {
    ServerStatistics serverRecorder = ServerStatistics.createAndStartRecord();
    if (StringUtils.isEmpty(refCache)) {
      refCache = "false";
    }
    Map<String, Object> passConditionMap = handleConditionParam(request, conQuery);
    Map<String, String> paramType = handleParamType(serviceID);
    PageResponseVo pageResponse = new PageResponseVo();

    List<QueryFiled> queryFileds = dbServerServiceImpl.selectServerField(serviceID);

    CfgExtsql cfgExtsql = cfgExtsqlService.selectCfgSqlByPrimary(serviceID);
    Integer ispagination = cfgExtsql.getIspagination();
    if (pageNO == null || "".equals(pageNO)) {
      pageNO = "1";
    }
    if (ispagination != null && ispagination == 1) {
      if (pageSize == null || pageSize.isEmpty()) {
        pageSize = "10";
      }
    } else {
      // 不分页查询的时候最多查询1万条，避免内存溢出
      pageSize = "10000";
    }
    DBServer server = dBServerServiceImpl.selectServerOne(serviceID);

    serverRecorder.recordSqlStartTime();
    try {
      CfgDb cfgDB = redisCacheComponent.cfgDBRedisCache(cfgExtsql.getDtDbKey());

      if(ParseSQLEnum.freemarker.getType().equals(server.getParamtype())){
        pageResponse = multipleTableServerService.multipleTableServerQueryPagination(cfgDB, pageNO, pageSize, passConditionMap , cfgExtsql, refCache);
      }else {
        pageResponse = multipleTableServerService.ognlQueryPagination(cfgDB, pageNO, pageSize, passConditionMap , cfgExtsql, queryFileds,paramType);
      }

      pageResponse.computeFirstRowPosition(pageNO, pageSize);

      if(XCommonUtils.isSingleResponseMode(server.getResponseMode())){
        List entityList = pageResponse.getRows();
        if(entityList == null || entityList.size() == 0)
          return JsonDataResult.responseSuccess(null, server.getResponseMode());

        if(entityList.size() > 1)
          throw new SingleModeMismatchException("rows size = " + entityList.size());

        return JsonDataResult.responseSuccess(entityList.get(0), server.getResponseMode());
      }


      return JsonDataResult.responseSuccess(pageResponse, server.getResponseMode());
    } catch(SingleModeMismatchException e) {

        logger.error("脚本查询异常: 查询数据大于一行" + e.getMessage());
        return JsonDataResult.responseError("脚本查询异常:  查询数据大于一行", server.getResponseMode());

    } catch (BusinessStatementException e) {
        return JsonDataResult.responseError("exceptionMessage: " + e.getExceptionMessage() + "\r\n customMessage: " + e.getCustomMessage());

    } catch (BaseException e) {
        logger.error("根据服务编码执行sql脚本获取信息异常：", e);
        return JsonDataResult.responseError("根据服务编码执行sql脚本获取信息异常：" + e.getExceptionVO().getDesc());

    } finally{
      serverRecorder.recordSqlEndTime();
      serverRecorder.recordServerEndTime();
      serverRecorder.setServerName(cfgExtsql.getServicename() + " (" + cfgExtsql.getGuid() + ")");
      serverRecorder.setSql(cfgExtsql.getDtSql());
      rabbitMQHelper.recordTimeConsumeIfNecessary(serverRecorder);
    }

  }
// todo 处理数组问题
	private Map<String, Object> handleConditionParam(HttpServletRequest request, String conQuery) {
		Map<String, String[]> requestParameterMap = request.getParameterMap();
        Map<String, Object> passConditionMap = XCommonUtils.convertJsonStringToMap(conQuery);
        for(Map.Entry<String, String[]> paramterEntry : requestParameterMap.entrySet()){
            String paramName = paramterEntry.getKey();
            String paramValue = paramterEntry.getValue()[0];
            if(XCommonUtils.filterRequestParam(paramName))
                continue;

            passConditionMap.put(paramName, paramValue);
        }
      return passConditionMap;
	}

  private Map<String, String> handleParamType(String serviceID) {
    Map<String, String> map = new HashMap<>();
    List<BaseSqlFieldType> byServiceId = cfgExtsqlService.findByServiceId(serviceID);
    byServiceId.forEach(e->{
      map.put(e.getFieldName(),e.getFieldJavaType());
    });
    return map;
  }

}

